using System;
using System.Collections.Generic;
using System.Text;
using System.Configuration;

namespace Microformats.ConfigurationSections
{

    internal interface ICommonConfig
    {
        /// <summary>
        /// Specifies the datatype of the microformat as a whole.
        /// </summary>
        string DataType
        {
            get; set;
        }

        /// <summary>
        /// Specifies the fields that are held in this configuration element.
        /// </summary>
        FieldCollection Fields { get; }

        /// <summary>
        /// Specifies the attribute type that we will be looking for that defines the root of the microformat in the HTML.
        /// If the root of the microformat is in a html 'class' attribute the specify 'class'.
        /// </summary>
        [System.Configuration.ConfigurationProperty("rootType", DefaultValue = "", IsKey = false, IsRequired = true)]
        string RootType
        {
            get;
            set;
        }
    }

    /// <summary>
    /// The Configuration Section that handles the creation of Microformats.
    /// </summary>
    public class MicroformatConfigSection : ConfigurationSection
    {
        public MicroformatConfigSection()
        { }

        [ConfigurationProperty("Microformats", IsDefaultCollection = false)]
        public MicroformatCollection Microformats
        {
            get { return (MicroformatCollection)base["Microformats"]; }
        }
    }

    /// <summary>
    /// The collection of microformat configuration elements
    /// </summary>
    public class MicroformatCollection : ConfigurationElementCollection
    {
        public MicroformatCollection()
        { }

        protected override ConfigurationElement CreateNewElement()
        {
            return new MicroformatElement();
        }

        protected override object GetElementKey(ConfigurationElement element)
        {
            return ((MicroformatElement)element).Type;
        }

        protected override string ElementName
        {
            get
            {
                return "Microformat";
            }
        }

        public override ConfigurationElementCollectionType CollectionType
        {

            get { return ConfigurationElementCollectionType.BasicMap; }

        }

        public MicroformatElement this[int index]
        {
            get { return (MicroformatElement)BaseGet(index); }
            set
            {
                if (BaseGet(index) != null)
                {
                    BaseRemoveAt(index);
                }

                BaseAdd(index, value);
            }
        }

        new public MicroformatElement this[string type]
        {
            get { return (MicroformatElement)BaseGet(type); }
        }

        public bool ContainsKey(string key)
        {
            bool result = false;
            object[] keys = BaseGetAllKeys();
            foreach (object obj in keys)          
            {
                if ((string)obj == key)
                {
                    result = true;
                    break;
                }
            }
            
            return result;
        }
    }

    /// <summary>
    /// A class representing a valid microformat configuration that the developers application will be able to parse.
    /// </summary>
    /// <remarks>
    /// If a developer using the framework wanted to only parse rel-tag in formation then only the following XML would be in the configuration file.
    ///  <MicroformatsSection>
    ///     <Microformats>
    ///         <Microformat type="rel-tag" rootType="rel" root="tag" />
    ///     </Microformats>
    ///  </MicroformatsSection>
    /// The above XML specifies that the rel-tag spec is to be searched for and it can will be found by searching for a 'rel' element with an attribute named tag.
    /// </remarks>
    public class MicroformatElement : ConfigurationElement, ICommonConfig
    {
        public MicroformatElement()
        { }

        /// <summary>
        /// The type of microformat that the framework is able to parse.  This property is the key in the configuration collection.
        /// </summary>
        [System.Configuration.ConfigurationProperty("type", DefaultValue = "", IsKey = true, IsRequired = true)]
        public string Type
        {
            get
            {
                return ((string)(base["type"]));
            }
            set
            {
                base["type"] = value;
            }
        }

        /// <summary>
        /// The type of microformat that the framework is able to parse.  This property is the key in the configuration collection.
        /// </summary>
        [System.Configuration.ConfigurationProperty("name", DefaultValue = "", IsKey = false, IsRequired = true)]
        public string Name
        {
            get
            {
                return ((string)(base["name"]));
            }
            set
            {
                base["name"] = value;
            }
        }

        /// <summary>
        /// Specifies the attribute type that we will be looking for that defines the root of the microformat in the HTML.
        /// If the root of the microformat is in a html 'class' attribute the specify 'class'.
        /// </summary>
        [System.Configuration.ConfigurationProperty("rootType", DefaultValue = "", IsKey = false, IsRequired = true)]
        public string RootType
        {
            get
            {
                return ((string)(base["rootType"]));
            }
            set
            {
                base["rootType"] = value;
            }
        }

        /// <summary>
        /// Specifies the attribute we will be looking for that defines the root of the microformat in the HTML.
        /// </summary>
        [System.Configuration.ConfigurationProperty("root", DefaultValue = "", IsKey = false, IsRequired = true)]
        public string Root
        {
            get
            {
                return ((string)(base["root"]));
            }
            set
            {
                base["root"] = value;
            }
        }

        /// <summary>
        /// Specifies the datatype of the microformat as a whole.
        /// </summary>
        [System.Configuration.ConfigurationProperty("dataType", DefaultValue = "", IsKey = false, IsRequired = true)]
        public string DataType
        {
            get
            {
                return ((string)(base["dataType"]));
            }
            set
            {
                base["dataType"] = value;
            }
        }

        [ConfigurationProperty("Fields", IsDefaultCollection = false)]
        public FieldCollection Fields
        {
            get { return (FieldCollection)base["Fields"]; }
        }
    }

    /// <summary>
    ///  name="post-office-box" dataType="System.String" plurality="Singular"
    /// </summary>
    public class FieldElement : ConfigurationElement, ICommonConfig
    {
        public FieldElement()
        { }

        /// <summary>
        /// The type of microformat that the framework is able to parse.  This property is the key in the configuration collection.
        /// </summary>
        [System.Configuration.ConfigurationProperty("name", DefaultValue = "", IsKey = true, IsRequired = true)]
        public string Name
        {
            get
            {
                return ((string)(base["name"]));
            }
            set
            {
                base["name"] = value;
            }
        }

        /// <summary>
        /// Specifies the attribute type that we will be looking for that defines the root of the microformat in the HTML.
        /// If the root of the microformat is in a html 'class' attribute the specify 'class'.
        /// </summary>
        [System.Configuration.ConfigurationProperty("dataType", DefaultValue = "", IsKey = false, IsRequired = true)]
        public string DataType
        {
            get
            {
                return ((string)(base["dataType"]));
            }
            set
            {
                base["dataType"] = value;
            }
        }

        /// <summary>
        /// Specifies the attribute type that we will be looking for that defines the root of the microformat in the HTML.
        /// If the root of the microformat is in a html 'class' attribute the specify 'class'.
        /// </summary>
        [System.Configuration.ConfigurationProperty("rootType", DefaultValue = "", IsKey = false, IsRequired = true)]
        public string RootType
        {
            get
            {
                return ((string)(base["rootType"]));
            }
            set
            {
                base["rootType"] = value;
            }
        }

        /// <summary>
        /// Specifies the attribute we will be looking for that defines the root of the microformat in the HTML.
        /// </summary>
        [System.Configuration.ConfigurationProperty("plurality", DefaultValue = "", IsKey = false, IsRequired = true)]
        public string Plurality
        {
            get
            {
                return ((string)(base["plurality"]));
            }
            set
            {
                base["plurality"] = value;
            }
        }

        [ConfigurationProperty("Fields", IsDefaultCollection = false)]
        public FieldCollection Fields
        {
            get { return (FieldCollection)base["Fields"]; }
        }
    }

    /// <summary>
    /// The collection of microformat configuration elements
    /// </summary>
    public class FieldCollection : ConfigurationElementCollection
    {
        public FieldCollection()
        { }

        protected override ConfigurationElement CreateNewElement()
        {
            return new FieldElement();
        }

        protected override object GetElementKey(ConfigurationElement element)
        {
            return ((FieldElement)element).Name;
        }

        protected override string ElementName
        {
            get
            {
                return "Field";
            }
        }

        public override ConfigurationElementCollectionType CollectionType
        {

            get { return ConfigurationElementCollectionType.BasicMap; }

        }

        public FieldElement this[int index]
        {
            get { return (FieldElement)BaseGet(index); }
            set
            {
                if (BaseGet(index) != null)
                {
                    BaseRemoveAt(index);
                }

                BaseAdd(index, value);
            }
        }

        new public FieldElement this[string type]
        {
            get { return (FieldElement)BaseGet(type); }
        }

        public bool ContainsKey(string key)
        {
            bool result = false;
            object[] keys = BaseGetAllKeys();
            foreach (object obj in keys)
            {
                if ((string)obj == key)
                {
                    result = true;
                    break;
                }
            }

            return result;
        }
    }

}
